﻿using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StackExchange.Redis.Extensions.CacheManager
{
    public class CacheManager
    {
        private const string Default_Region = "default";

        private readonly IDatabase _database;

        public CacheManager(IDatabase database)
        {
            _database = database;
        }

        public bool Add<T>(string key, string region, T value)
        {
            ItemCache<T> item = new ItemCache<T>()
            {
                Key = key,
                Value = value,
                ExpireDate = DateTime.MaxValue
            };

            return _database.HashSet(region, key, item.Serialize<T>(), When.Exists);
        }

        public bool Add<T>(string key, string region, T value, TimeSpan expireDate)
        {
            ItemCache<T> item = new ItemCache<T>()
            {
                Key = key,
                Value = value,
                ExpireDate = DateTime.UtcNow.Add(expireDate)
            };

            return _database.HashSet(region, key, item.Serialize<T>(), When.Exists);
        }

        public bool Add<T>(string key, T value)
        {
            ItemCache<T> item = new ItemCache<T>()
            {
                Key = key,
                Value = value,
                ExpireDate = DateTime.MaxValue
            };

            return _database.HashSet(Default_Region, key, item.Serialize<T>(), When.Exists);
        }

        public bool Add<T>(string key, T value, TimeSpan expireDate)
        {
            ItemCache<T> item = new ItemCache<T>()
            {
                Key = key,
                Value = value,
                ExpireDate = DateTime.UtcNow.Add(expireDate)
            };

            return _database.HashSet(Default_Region, key, item.Serialize<T>(), When.Exists);
        }

        public bool Set<T>(string key, string region, T value)
        {
            ItemCache<T> item = new ItemCache<T>()
            {
                Key = key,
                Value = value,
                ExpireDate = DateTime.MaxValue
            };

            return _database.HashSet(region, key, item.Serialize<T>());
        }

        public bool Set<T>(string key, string region, T value, TimeSpan expireDate)
        {
            ItemCache<T> item = new ItemCache<T>()
            {
                Key = key,
                Value = value,
                ExpireDate = DateTime.UtcNow.Add(expireDate)
            };

            return _database.HashSet(region, key, item.Serialize<T>());
        }

        public bool Set<T>(string key, T value)
        {
            ItemCache<T> item = new ItemCache<T>()
            {
                Key = key,
                Value = value,
                ExpireDate = DateTime.MaxValue
            };

            return _database.HashSet(Default_Region, key, item.Serialize<T>());
        }

        public bool Set<T>(string key, T value, TimeSpan expireDate)
        {
            ItemCache<T> item = new ItemCache<T>()
            {
                Key = key,
                Value = value,
                ExpireDate = DateTime.UtcNow.Add(expireDate)
            };

            return _database.HashSet(Default_Region, key, item.Serialize<T>());
        }

        public T Get<T>(string key, string region)
        {
            var hashValue = _database.HashGet(region, key);
            if(!hashValue.IsNull)
            {
                var item = JsonConvert.DeserializeObject<ItemCache<T>>(hashValue);
                if (item != null && item.ExpireDate > DateTime.UtcNow)
                {
                    return item.Value;
                }
                else
                {
                    Delete(region, key);
                }
            }
            return default(T);
        }

        public T Get<T>(string key)
        {
            var hashValue = _database.HashGet(Default_Region, key);
            if (!hashValue.IsNull)
            {
                var item = JsonConvert.DeserializeObject<ItemCache<T>>(hashValue);
                if (item != null && item.ExpireDate > DateTime.UtcNow)
                    return item.Value;
                else
                {
                    Delete(Default_Region, key);
                }
            }
            return default(T);
        }

        public bool Delete(string key)
        {
            return _database.HashDelete(Default_Region, key);
        }

        public bool Delete(string key, string region)
        {
            return _database.HashDelete(region, key);
        }


        public bool Exist(string key)
        {
            return _database.HashExists(Default_Region, key);
        }

        public bool Exist(string key, string region)
        {
            return _database.HashExists(region, key);
        }

        public List<string> GetAll(string region)
        {
            var entries = _database.HashGetAll(region);
            return entries.Select(s => s.Name.ToString()).ToList();
        }
    }
}
